/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 d3leaf@126.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.mapperdb.helper;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

/**
 * 注解 代理类
 * An example of using <code>Reflect</code> is <code><pre>
 * AnntHandler.use(Result.class).newProxyInstance();
 * AnntHandler.use(Result.class).set("id", true).newProxyInstance();
 * 
 * @author Administrator
 */
@SuppressWarnings("unchecked")
public class AnntHandler implements InvocationHandler {
	protected final Class<?> anntClass;
	protected final Method[] interfaceMethods;
	protected final Map<String, Object> valMap;
	protected final Map<String, Boolean> isNullValueAsDefaultValMap;

	public AnntHandler(Class<?> anntClass) {
		this.anntClass = anntClass;
		this.interfaceMethods = anntClass.getDeclaredMethods();
		this.valMap = new HashMap<String, Object>();
		this.isNullValueAsDefaultValMap = new HashMap<String, Boolean>();
	}

	public static <T extends Annotation> AnntHandler use(Class<T> anntClass) {
		return new AnntHandler(anntClass);
	}

	/**
	 * set 值
	 * @param name
	 * @param val
	 * @param isNullValueAsDefaultVal (为 null 时 是否取默认值)
	 * @return 
	 */
	public AnntHandler set(String name, Object val, boolean isNullValueAsDefaultVal) {
		valMap.put(name, val);
		isNullValueAsDefaultValMap.put(name, isNullValueAsDefaultVal);
		return this;
	}

	public AnntHandler set(String name, Object val) {
		return set(name, val, true);
	}

	public Object get(String name) throws NoSuchMethodException, SecurityException {
		Object val = valMap.get(name);
		Boolean asDefault = isNullValueAsDefaultValMap.get(name);
		if (val == null && (asDefault == null || asDefault)) {
			valMap.put(name, val = anntClass.getMethod(name).getDefaultValue());
		}
		return val;
	}

	public <T extends Annotation> T newProxyInstance() {
		return (T) Proxy.newProxyInstance(anntClass.getClassLoader()//
				, new Class[] { anntClass }//
				, this);
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		String name = method.getName();
		if ("toString".equals(name)) {
			StringBuffer sb = new StringBuffer("@").append(anntClass.getName()).append("(");
			boolean isFirst = true;
			for (Method m : interfaceMethods) {
				String key = m.getName();
				if (!isFirst) sb.append(", ");
				isFirst = false;
				sb.append(key).append("=").append(get(key));
			}
			sb.append(")");
			return sb.toString();
		}
		return get(name);
	}
}
